package com.hitqz.robot.biz.listener;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.cache.Cache;
import com.hitqz.robot.api.business.dto.AddWarningRecordDto;
import com.hitqz.robot.api.business.dto.RobotAddDispatchDto;
import com.hitqz.robot.api.business.dto.SubscriptTopicDto;
import com.hitqz.robot.api.business.entity.RobotEntity;
import com.hitqz.robot.api.business.entity.RobotGroupEntity;
import com.hitqz.robot.api.business.entity.RobotWarningRecordEntity;
import com.hitqz.robot.biz.service.JobCachesService;
import com.hitqz.robot.biz.service.RobotGroupService;
import com.hitqz.robot.biz.service.RobotService;
import com.hitqz.robot.biz.service.RobotWarningRecordService;
import com.hitqz.robot.biz.websocket.endpoint.SubscriptionEndpoint;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author xupkun
 * @date 2024/7/31
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class RobotOtherEventListener {


    private final RobotService robotService;

    private final RobotGroupService robotGroupService;

    private final RobotWarningRecordService robotWarningRecordService;

    private final JobCachesService jobCachesService;

    private static final ObjectMapper objectMapper = new ObjectMapper();

    public static ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10,20,
            1L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<Runnable>(20),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.DiscardPolicy());

    @EventListener
    public void listenerRobotOnline(RobotAddDispatchDto robotAddDispatchDto) {
        log.info("有机器人状态修改,重新进入机器人计算");
        RobotEntity robotEntity = robotService.selectByRobotSn(robotAddDispatchDto.getRobotSn());
        if (robotEntity==null){
            return;
        }
        Cache<String, Long> idleTask = SpringUtil.getBean("idleTask");
        idleTask.put( robotEntity.getRobotSn(), System.currentTimeMillis());
        int level = 0;
        String content = "";
        boolean canWarning = false;
        // 判断是否能进入调度组计算
        List<RobotEntity> robotEntityList = robotService.
                list(Wrappers.<RobotEntity>lambdaQuery().eq(RobotEntity::getGroupId, robotEntity.getGroupId())
                        .ne(RobotEntity::getRobotSn, robotEntity.getRobotSn())
                );
        if (CollectionUtil.isNotEmpty(robotEntityList)) {
            // 判断是否存在调度条件
            // 地图是否都一致
            List<RobotEntity> otherRobot = robotEntityList.stream().filter(
                    r-> !Objects.equals(r.getMapCode(), robotEntity.getMapCode())).collect(Collectors.toList());
            log.info("其他的机器人{}", otherRobot.stream().map(RobotEntity::getRobotSn).collect(Collectors.joining("-")));
            if (CollectionUtil.isNotEmpty(otherRobot)) {
                // 存在不一致,进行告警，不进入调度范围，因为坐标可能不对
                canWarning = true;
                content = robotEntity.getRobotName() + "所处调度组有机器人存在地图不一致，无法进入调度范围";
                level = 1;
            }
        }
        if (canWarning) {
            log.info("some error according:" + content);
            AddWarningRecordDto warningRecordDto = new AddWarningRecordDto();
            warningRecordDto.setLevel(level);
            warningRecordDto.setContent(content);
            SpringUtil.getApplicationContext().publishEvent(warningRecordDto);
        } else {
            threadPool.execute(()-> {
                synchronized (this) {
                    RobotGroupEntity robotGroupEntity = robotGroupService.getById(robotEntity.getGroupId());
                    Cache<Integer, List<RobotEntity>> posInfoDtoCache = SpringUtil.getBean("robotDispatch");
                    Integer groupId = robotAddDispatchDto.getOldGroupId() == null ?
                            robotGroupEntity.getId() : robotAddDispatchDto.getOldGroupId();
                    List<RobotEntity> robotEntityMultiKeyMap = posInfoDtoCache.getIfPresent(groupId);
                    if (robotEntityMultiKeyMap == null) {
                        robotEntityMultiKeyMap = Lists.newArrayList();
                    }
                    Optional<RobotEntity> findRobot = robotEntityMultiKeyMap.stream()
                            .filter(t-> t.getRobotSn().equals(robotEntity.getRobotSn())).findFirst();
                    if (findRobot.isPresent()) {
                        // 移除之前的
                        robotEntityMultiKeyMap.remove(findRobot.get());
                        posInfoDtoCache.put(groupId, robotEntityMultiKeyMap);
                    }
                    log.info("{} 开始进入写入调度组计算 {}", robotGroupEntity.getName(), robotEntity.getRobotName());
                    robotEntityMultiKeyMap.add(robotEntity);
                    List<RobotEntity> newGroup = posInfoDtoCache.getIfPresent(robotGroupEntity.getId());
                    if (CollectionUtil.isEmpty(newGroup)) {
                        newGroup = Lists.newArrayList();
                    }
                    if (newGroup.stream().noneMatch(robot-> robot.getRobotSn().equals(robotEntity.getRobotSn()))) {
                        newGroup.add(robotEntity);
                    };
                    posInfoDtoCache.put(robotGroupEntity.getId(), newGroup);
                    log.info("{} 最终调度组的内容: {}", robotGroupEntity.getName(),
                            newGroup.stream().map(RobotEntity::getRobotSn).collect(Collectors.joining("|"))
                            );
                }
            });

        }
    }

    @EventListener
    public void listenerWarning(AddWarningRecordDto addWarningRecordDto) {
        RobotWarningRecordEntity robotWarningRecord = new RobotWarningRecordEntity();
        robotWarningRecord.setFlag("0");
        robotWarningRecord.setContent(addWarningRecordDto.getContent());
        robotWarningRecord.setServiceId("系统告警");
        robotWarningRecord.setTime(LocalDateTime.now());
        robotWarningRecord.setTitle("系统告警");
        robotWarningRecord.setType("0");
        robotWarningRecord.setLevel(addWarningRecordDto.getLevel());
        robotWarningRecordService.save(robotWarningRecord);
    }


    /**
     * websocket 关注话题-推送消息
     * @param subscriptTopicDto
     */
    @EventListener
    public void onSubScriptTopic(SubscriptTopicDto subscriptTopicDto) {
        String topic = subscriptTopicDto.getTopic();
        if (topic.equals("jobCaches")) {
            // 缓存任务，推送数据
            try {
                // 分组
                SubscriptionEndpoint.broadcast("jobCaches", objectMapper.writeValueAsString(jobCachesService.sortType()));
            } catch (Exception e) {
                log.error("[ws][subscribe]broadcast jobCaches error:{}",e.getMessage());
            }
        }
    }



}
